﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Input;
using System.Reflection;

namespace X3DXamlXna
{
    //l'idea alla base di questa classe e' che il route deve essere il piu' astratto possibile in maniera tale da demandare
    //i side effects nelle specifiche classi su cui avviene il bind perche altrimenti sarebbe stato oneroso da gestire tutti
    //i casi in una unica classe
    //Le fasi di bind avverranno secondo questa serie
    //1-Scorro l'albero x3d in cerca del nodi con il DEF == FromNode e anche DEF == ToNode
    //2-Una volta trovato il FromNode nell albero mi faccio "gettare" la proprieta' con nome FromField
    //3-"Setto" il valore appena ottenuto dal punto 2 nella prorieta del ToNode con la proprieta' con nome ToField

    public interface IRouteComponent
    {
        void add(Object FromNode, Object ToNode, string FromField, string ToField);
    }
    //hi
    class RouteComponent : GameComponent , IRouteComponent
    {
        private Type t;
        private string value;
        //lista di route da andare a servire
        private List<FromTo> fromto;
        

        public RouteComponent(Game game)
            : base(game)
        {
            game.Services.AddService(typeof(IRouteComponent), this);
            fromto = new List<FromTo>();
        }
        public override void Initialize()
        {
           base.Initialize();
        }

        public void add(Object FromNode, Object ToNode, string FromField, string ToField)
        {
            fromto.Add(new FromTo(FromNode,ToNode,FromField,ToField));
        }

        public override void Update(GameTime gameTime)
        {
            //per ciascun route nella lista di route
            foreach (FromTo elem in fromto)
            {
                //getto la proprieta fromfield dal fromnode di cui so gia che sara' di tipo string
                t = Type.GetType("X3DXamlXna." + elem.FromNode.GetType().Name);
                value = (string)t.InvokeMember(elem.FromField, BindingFlags.GetField | BindingFlags.GetProperty, null, elem.FromNode, new object[] { });
                //e la setto su tofield di tonode
                t = Type.GetType("X3DXamlXna." + elem.ToNode.GetType().Name);
                t.InvokeMember(elem.ToField, BindingFlags.SetProperty, null, elem.ToNode, new object[] { value });
                //a questo punto a route non interessa cosa avverra' agli oggetti in seguito al loro aggiornamento di stato
                //perche' saranno loro a gestire queste modifiche e ad agire di conseguenza mantenendo cosi il route generale
                //efficente e capace di servire qualsiasi tipo di bind anche quelli "sensa senso" che sono permessi da X3D :P
                
            }
            
            base.Update(gameTime);
        }        
    }
    class FromTo
    {
        //sia lodato f# (anche gli altri linguaggi funzionali tranne quello di salibra :P) che ti evita di fare 
        //queste porcate fatte su misura
        public Object FromNode { get; private set; }
        public Object ToNode { get; private set; }
        public string FromField { get; private set; }
        public string ToField { get; private set; }
        public FromTo(Object fn, Object tn, string ff, string tf)
        {
            FromNode = fn;
            ToNode = tn;
            FromField = ff;
            ToField = tf;            
        }
    }
}
